package cmp.viewer.table;

/***********************************************************
 * Defines all columns
 * They are rendered in SortTable (e.g. if you want to change how a double is printed)
 */
import java.util.Iterator;
import java.util.Vector;

import cmp.main.Globals;

public class FieldData {
	//Main table for the different query modes
	public static final String POG_TABLE = "pog_groups";
	public static final String MEMBER_TABLE = "pog_members";
	public static final String UNITRANS_TABLE = "unitrans";
	
	public static final String maxPCC="LmaxPCC"; // database record for special processing in sortTable
	//****************************************************************************
	//* Static methods
	//* To add a column: Simply
	//*		(1) Add to the following three arrays, (2) add to getPogFields or getUnitransFields
	//*		(3) Add to row POG_SECTION_IDX or UNITRANS_SECTION_IDX arrays 
	//****************************************************************************
	//POG settings
	public static final String ROWNUM = "Row #";
	public static final String CLUSTERID = "Cluster ID";
	private static final String [] POG_COLUMN_SELECT = 			{ 	
						ROWNUM, CLUSTERID, "Count", "Taxa", "Method",  
						"Descript", "Percent", 
						"hitID", "Eval", "Species", "Type", "Tag",  "Len",
						"perPCC", "maxPCC"
																};
	private static final String [] POG_DESCRIPTION_SELECT = 	{ 	
			"Row number", "Name of Cluster", "Number of sequences in group", 
			"Number of taxa in group (e.g. 2xN is two taxa where at least one has multiple unitrans", 
			"Method used to create group", 					
						
			"Description of majority hit","Percent members with majority hit",
			"Majority hit identifier", "Best E-value for the majority hit",	
			"Species of majority hit",
			"Type of majority hit", 
			"Taxonomy of majority hit", 
			"Length of majority hit",
			"Percent of the pairs with PCC>=" + Globals.PCCcutoff,
			"Maximum PCC (Pearson Correlation Coefficient) of RPKMs"
																};
	public static final boolean [] POG_SELECTIONS = 			{ 	
						true, true, true, false, false, 
						true, true, false, 
						false, false, 
						false, false, false,
						false, false
	};
	// IDX goes with first 3 sets of non-dynamic columns, e.g. 2nd row ends with col[7] and has "" section
	public static final String [] POG_SECTION_NAMES =			
		{ "General",  
		"Majority Hit",  
		"Percent pairs with PCC>=" + Globals.PCCcutoff,
		"Percent sequences with RPKM>=" + Globals.RPKMcutoff, 
		"Species member counts",
		"Percent sequences with DE<" + Globals.DEcutoff
		};
	public static int [] POG_SECTION_IDX = { 5, 13, 15 };
	
	public static String [] getPOGColumnSections() { return POG_SECTION_NAMES; }
	
	public static int [] getPOGColumnSectionIdx(int nAsm, int nLib, int nDE) {
		int [] retVal = new int[POG_SECTION_IDX.length + 3];
		for(int x=0; x<POG_SECTION_IDX.length; x++) retVal[x] = POG_SECTION_IDX[x];
		retVal[POG_SECTION_IDX.length] = 	POG_SECTION_IDX[POG_SECTION_IDX.length -1] + nLib;
		retVal[POG_SECTION_IDX.length + 1] = POG_SECTION_IDX[POG_SECTION_IDX.length -1] + nAsm + nLib;
		retVal[POG_SECTION_IDX.length + 2] = POG_SECTION_IDX[POG_SECTION_IDX.length -1] + nAsm + nLib + nDE;		
		return retVal; 
	}

	public static String [] getPOGColumnSelect(String [] asm, String [] lib, String [] de) {
		String [] retVal = new String[POG_COLUMN_SELECT.length + asm.length + lib.length + de.length];
		for(int x=0; x<POG_COLUMN_SELECT.length; x++) retVal[x] = POG_COLUMN_SELECT[x];
		
		int offset = POG_COLUMN_SELECT.length;
		for(int x=0; x<lib.length; x++) retVal[x + offset] = lib[x];
		offset += lib.length;
		for(int x=0; x<asm.length; x++) retVal[x + offset] = asm[x];
		offset += asm.length;
		for(int x=0; x<de.length; x++) retVal[x + offset] = de[x];
		return retVal; 
	}
	
	public static String [] getPOGDescriptionSelect(String [] asm, String [] lib, String [] de) {
		String [] retVal = new String[POG_DESCRIPTION_SELECT.length + asm.length + lib.length + de.length];
		for(int x=0; x<POG_DESCRIPTION_SELECT.length; x++) retVal[x] = POG_DESCRIPTION_SELECT[x];
		int offset = POG_DESCRIPTION_SELECT.length;
	
		for(int x=0; x<lib.length; x++)
			retVal[x + offset] = "Percent of RPKM>= " + Globals.RPKMcutoff + " for cluster for library " + lib[x];	
		offset += lib.length;
		for(int x=0; x<asm.length; x++)
			retVal[x + offset] = "Number of members in cluster from dataset " + asm[x];
		offset += asm.length;
		for(int x=0; x<de.length; x++)
			retVal[x + offset] = "Percent of DE< " + Globals.DEcutoff + " for cluster for DE " + de[x];	
		return retVal; 
	}
		
	// set default columns on
	public static boolean [] getPOGSelections(int nAsm, int nLib, int nDE) {
		boolean [] retVal = new boolean[POG_SELECTIONS.length + nAsm + nLib + nDE];
		for(int x=0; x<POG_SELECTIONS.length; x++) retVal[x] = POG_SELECTIONS[x];
		int offset = POG_SELECTIONS.length;
	
		for(int x=0; x<nLib; x++) retVal[x + offset] = false;
		offset += nLib;
		for(int x=0; x<nAsm; x++) retVal[x + offset] = true;
		offset += nAsm;
		for(int x=0; x<nDE; x++) retVal[x + offset] = false;
		return retVal; 
	}
	
	// The actual formating is in SortTable. 
	public static FieldData getPogFields(String [] asm, String [] lib, String [] de) {
		FieldData fd = new FieldData();
		// don't forget to renumber if insert in the middle
		fd.addField(POG_COLUMN_SELECT[0], Integer.class, null, null, "ROWNUM");
		fd.addField(POG_COLUMN_SELECT[1], String.class, POG_TABLE, "PGstr", "PGSTR");
		fd.addField(POG_COLUMN_SELECT[2], Integer.class, POG_TABLE, "count", "COUNT");
		fd.addField(POG_COLUMN_SELECT[3], Integer.class, POG_TABLE, "taxa", "TAXA");
		fd.addField(POG_COLUMN_SELECT[4], String.class, "POGMETHOD", "PMstr", "PMSTR");
			
		fd.addField(POG_COLUMN_SELECT[5], String.class, "POGHITS", "description", "BESTHITDESCRIP");
		fd.addField(POG_COLUMN_SELECT[6], Integer.class, POG_TABLE, "score", "BESTSCORE");
		fd.addField(POG_COLUMN_SELECT[7], String.class, "POGHITS", "HITstr", "HITSTR");
		fd.addField(POG_COLUMN_SELECT[8], Double.class, POG_TABLE, "e_value", "EVALUE");	
		fd.addField(POG_COLUMN_SELECT[9], String.class, "POGHITS", "species", "BESTHITSPECIES");
		fd.addField(POG_COLUMN_SELECT[10], String.class, "POGHITS", "dbtype", "BESTHITTYPE");
		fd.addField(POG_COLUMN_SELECT[11], String.class, "POGHITS", "taxonomy", "BESTHITTAXO");
		fd.addField(POG_COLUMN_SELECT[12], Long.class, "POGHITS", "length", "BESTHITLENGTH");
		
		fd.addField(POG_COLUMN_SELECT[13], String.class, POG_TABLE, "LperPCC", "PERPCC");
		fd.addField(POG_COLUMN_SELECT[14], String.class, POG_TABLE, "LmaxPCC", "MAXPCC"); // ref in SortTable
		
		for(int x=0; x<lib.length; x++) {
			fd.addField(lib[x], Double.class, POG_TABLE, Globals.PRE_LIBCNT + lib[x], "LIB" + x);
		}
		for(int x=0; x<asm.length; x++) {
			fd.addField(asm[x], Integer.class, POG_TABLE, Globals.PRE_ASM + asm[x], "ASSEM" + x);
		}
		for(int x=0; x<de.length; x++) {
			fd.addField(de[x], Double.class, POG_TABLE, Globals.PRE_DECNT + de[x], "DE" + x);
		}

		
		fd.addJoin("pog_method", "pog_groups.PMid = POGMETHOD.PMid", "POGMETHOD");
		fd.addJoin("unique_hits", "pog_groups.HITid = POGHITS.HITid", "POGHITS");

		fd.addField("POGID", Long.class, POG_TABLE, "PGid", "PGID");
		
		return fd;
	}
	
	/** Member settings **/
	private static final String [] MEMBER_COLUMN_SELECT = 	{ 	
							"Row #", "Cluster ID", "Seq ID", "# Align", "Length", 
							"Total Count", "Total RPKM", "Count List", "RPKM List ",
							"hitID", "Eval", "Descript", "Species","Type", "Tag", "Len"
																};
	private static final String [] MEMBER_DESCRIPTION_SELECT = 	{ 	
							"Row number", "Name of Cluster", "Name of sequence", 
							"Number of alignments (assembled sequences only)", "Sequence length", 
							"Sum of the counts for all libraries", "Sum of RPKM for all libraries", 
							"List of libraries with counts", "List of libraries with RPKM",
							"Best hit name", "Best hit e-value", 
							"Best hit description", "Best hit species",
							"Best hit type", "Best hit taxonomy", "Best hit length"
																	};	
	public static final boolean [] MEMBER_SELECTIONS = 		{ 	
								true, false, true, 
								false, true,
								false, false, 
								false, false,
								false, true, true, false,
								false, false, false,
																};
	//Sections headers, leave blank for another row
	public static final String [] MEMBER_SECTION_NAMES =		
		{ "General", "",  "Best Annotation Hit", "Library RPKM", "Methods", "Differential Expression", "" };
	
	public static final int [] MEMBER_SECTION_IDX =	{ 5, 9, 16};

	public static String [] getMemberColumnSections() { return MEMBER_SECTION_NAMES; }
	
	public static int [] getMemberColumnSectionIdx(int nLib, int nDE, int nMet) {
		int nSection = MEMBER_SECTION_IDX.length;
		int nStart = MEMBER_SECTION_IDX[nSection -1]; // start of dynamic
		int [] retVal = new int[nSection + 3];
		
		for(int x=0; x<nSection; x++) retVal[x] = MEMBER_SECTION_IDX[x];
		retVal[nSection] = 		nStart + nLib;
		retVal[nSection + 1] = 	nStart + nLib + nMet;
		retVal[nSection + 2] = 	nStart + nLib + nDE + nMet;
		return retVal; 
	}
	
	public static String [] getMemberColumnSelect(String [] lib, String [] de, String [] methods) { 
		int offset = MEMBER_COLUMN_SELECT.length;
		String [] retVal = new String[offset + lib.length + de.length + methods.length];
		for(int x=0; x<offset; x++) retVal[x] = MEMBER_COLUMN_SELECT[x];

		for(int x=0; x<lib.length; x++) retVal[x + offset] = lib[x];
		offset += lib.length;
		for(int x=0; x<methods.length; x++) retVal[x + offset] = methods[x];		
		offset += methods.length;
		for(int x=0; x<de.length; x++) retVal[x + offset] = de[x];
		return retVal; 
	}
	
	public static String [] getMemberDescriptionSelect(String [] lib, String [] de, String [] methods) { 
		int offset = MEMBER_DESCRIPTION_SELECT.length;
		String [] retVal = new String[offset + lib.length + de.length + methods.length];
		for(int x=0; x<offset; x++) retVal[x] = MEMBER_DESCRIPTION_SELECT[x];

		for(int x=0; x<lib.length; x++) retVal[x + offset] = "Library count for dataset " + lib[x];
		offset += lib.length;
		for(int x=0; x<methods.length; x++) retVal[x + offset] = "Method member name " + methods[x];		
		offset += methods.length;
		for(int x=0; x<de.length; x++) retVal[x + offset] = "Differential expression for dataset " + de[x];
		return retVal; 
	}
	
	public static boolean [] getMemberSelections(int nLib, int nDE, int nMet) {
		int offset = MEMBER_SELECTIONS.length;
		boolean [] retVal = new boolean[offset + nLib + nDE + nMet];
		for(int x=0; x<offset; x++) retVal[x] = MEMBER_SELECTIONS[x];

		for(int x=0; x<nLib; x++) retVal[x + offset] = true;
		offset += nLib;
		for(int x=0; x<nMet; x++) retVal[x + offset] = true;		
		offset += nMet;
		for(int x=0; x<nDE; x++) retVal[x + offset] = true;
		return retVal; 
	}
			                       
	public static FieldData getMemberFields(String [] lib, String [] de, String [] methods) {
		FieldData fd = new FieldData();

		fd.addField(MEMBER_COLUMN_SELECT[0], Integer.class, null, null, "ROWNUM");
		fd.addField(MEMBER_COLUMN_SELECT[1], String.class, MEMBER_TABLE, "PGstr", "POGID");
		fd.addField(MEMBER_COLUMN_SELECT[2], String.class, "UNITRANSTABLE", "UTstr", "POGSTR");
		fd.addField(MEMBER_COLUMN_SELECT[3], Long.class, "UNITRANSTABLE", "numAlign", "NUMALIGN");
		fd.addField(MEMBER_COLUMN_SELECT[4], Long.class, "UNITRANSTABLE", "aaLen", "LENGTH");
		fd.addField(MEMBER_COLUMN_SELECT[5], Long.class, "UNITRANSTABLE", "totExp", "TOTALEXP");
		fd.addField(MEMBER_COLUMN_SELECT[6], Long.class, "UNITRANSTABLE", "totExpN", "TOTALEXPN");
		fd.addField(MEMBER_COLUMN_SELECT[7], String.class, "UNITRANSTABLE", "expList", "EXPLIST");
		fd.addField(MEMBER_COLUMN_SELECT[8], String.class, "UNITRANSTABLE", "expListN", "EXPLISTN");
		
		fd.addField(MEMBER_COLUMN_SELECT[9], String.class, "HITSTABLE", "HITstr", "HITSTR");
		fd.addField(MEMBER_COLUMN_SELECT[10], Double.class, "UNITRANSTABLE", "e_value", "EVALUE");
		fd.addField(MEMBER_COLUMN_SELECT[11], String.class, "HITSTABLE", "description", "BESTHITDESCRIP");
		fd.addField(MEMBER_COLUMN_SELECT[12], String.class, "HITSTABLE", "species", "BESTHITSPECIES");
		fd.addField(MEMBER_COLUMN_SELECT[13], String.class, "HITSTABLE", "dbtype", "BESTHITTYPE");
		fd.addField(MEMBER_COLUMN_SELECT[14], String.class, "HITSTABLE", "taxonomy", "BESTHITTAXO");	
		fd.addField(MEMBER_COLUMN_SELECT[15], Long.class, "HITSTABLE", "length", "BESTHITLENGTH");

		for(int x=0; x<lib.length; x++) {
			fd.addField(lib[x], Double.class, "UNITRANSTABLE", Globals.PRE_LIB + lib[x], "LIB" + x);
		}
		for(int x=0; x<methods.length; x++) {
			fd.addField(methods[x], String.class, "UNITRANSTABLE", methods[x], "MET" + x);
		}
		for(int x=0; x<de.length; x++) {
			fd.addField(de[x], Double.class, "UNITRANSTABLE", Globals.PRE_DE + de[x], "DE" + x);
		}


		fd.addField("AASeq", String.class, "UNITRANSTABLE", "aaSeq", "AASEQ");
		fd.addField("UTID", String.class, "UNITRANSTABLE", "UTid", "UTRANSID");
		
		fd.addJoin("unitrans", "pog_members.UTid = UNITRANSTABLE.UTid", "UNITRANSTABLE");
		fd.addJoin("unique_hits", "UNITRANSTABLE.HITid = HITSTABLE.HITid", "HITSTABLE");

		return fd;
	}
                 
	/*** Sequence settings ***/
	private static final String [] UNITRANS_COLUMN_SELECT = 	{ 	
						"Row #", "Seq ID", "# Align", "Length", 
						"Total Count", "Total RPKM", "Count List", "RPKM List ",
						"H-ID", "H-Eval", "H-Desc", "H-Species",
						"H-Type", "H-Tag", "H-Len"
																};
	private static final String [] UNITRANS_DESCRIPTION_SELECT = 	{ 	
				"Row number", "Name of sequence", "Number of alignments (assembled only)", "Sequence length", 
				"Sum of the raw counts for all libraries", "Sum of RPKM for all libraries", 
				"List of libraries and raw counts", "List of libraries and RPKM",
				"Best hit name", "Best hit e-value", 
				"Best hit description", "Best hit species", 
				"Best hit type", "Best hit taxonomy", "Best hit length"
																	};	

	public static final boolean [] UNITRANS_SELECTIONS = 		{ 	
						true, true, false, true,
						false, false, false, false,
						false, true, true, false,
						false, false, false,
						};
	
	//Sections headers, leave blank for another row
	public static final String [] UNITRANS_SECTION_NAMES =		
		{ "General", "", "Best Annotation Hit", "Library RPKM",  "Methods",  "Differential Expression", "" };
	
	public static final int [] UNITRANS_SECTION_IDX = { 4, 8, 15 };

	public static String [] getUnitransColumnSections() { return UNITRANS_SECTION_NAMES; }
	
	public static int [] getUnitransColumnSectionIdx(int nLib, int nDE, int nMet) {
		int nSection = UNITRANS_SECTION_IDX.length;
		int nStart = UNITRANS_SECTION_IDX[nSection -1];
		int [] retVal = new int[nSection + 3];
		
		for(int x=0; x<nSection; x++) retVal[x] = UNITRANS_SECTION_IDX[x];
		retVal[nSection] = 		nStart + nLib;
		retVal[nSection+1] = 	nStart + nLib + nMet;
		retVal[nSection + 2] = 	nStart + nLib + nDE + nMet;		
		return retVal; 
	}

	public static String [] getUnitransColumnSelect(String [] lib, String [] de, String [] methods) { 
		int offset = UNITRANS_COLUMN_SELECT.length;
		String [] retVal = new String[offset + lib.length + de.length + methods.length];
		for(int x=0; x<offset; x++) retVal[x] = UNITRANS_COLUMN_SELECT[x];
	
		for(int x=0; x<lib.length; x++) retVal[x + offset] = lib[x];
		offset += lib.length;
		
		for(int x=0; x<methods.length; x++) retVal[x + offset] = methods[x];		
		offset += methods.length;

		for(int x=0; x<de.length; x++) retVal[x + offset] = de[x];
		
		return retVal; 
	}
	
	public static String [] getUnitransDescriptionSelect(String [] lib, String [] de, String [] methods) { 
		int offset = UNITRANS_DESCRIPTION_SELECT.length;
		String [] retVal = new String[offset + lib.length + de.length + methods.length];
		for(int x=0; x<offset; x++) retVal[x] = UNITRANS_DESCRIPTION_SELECT[x];
	
		for(int x=0; x<lib.length; x++) retVal[x + offset] = "Library count for " + lib[x];
		offset += lib.length;
		for(int x=0; x<methods.length; x++) retVal[x + offset] = "Method member name " + methods[x];		
		offset += methods.length;
		for(int x=0; x<de.length; x++) retVal[x + offset] = "Expression level for " + de[x];
		return retVal; 
	}
	
	public static boolean [] getUnitransSelections(int nLib, int nDE, int nMet) {
		int offset = UNITRANS_SELECTIONS.length;
		boolean [] retVal = new boolean[offset + nLib + nDE + nMet];
		for(int x=0; x<offset; x++) retVal[x] = UNITRANS_SELECTIONS[x];
		
		for(int x=0; x<nLib; x++) retVal[x + offset] = true;
		offset += nLib;
		for(int x=0; x<nMet; x++) retVal[x + offset] = false;		
		offset += nMet;
		for(int x=0; x<nDE; x++) retVal[x + offset] = true;
		return retVal; 
	}
			                       
	public static FieldData getUnitransFields(String [] lib, String [] de, String [] methods) {
		FieldData fd = new FieldData();

		fd.addField(UNITRANS_COLUMN_SELECT[0], Integer.class, null, null, "ROWNUM");
		fd.addField(UNITRANS_COLUMN_SELECT[1], String.class, UNITRANS_TABLE, "UTstr", "POGSTR");
		fd.addField(UNITRANS_COLUMN_SELECT[2], Long.class, UNITRANS_TABLE, "numAlign", "NUMALIGN");
		fd.addField(UNITRANS_COLUMN_SELECT[3], Long.class, UNITRANS_TABLE, "aaLen", "LENGTH");
		fd.addField(UNITRANS_COLUMN_SELECT[4], Long.class, UNITRANS_TABLE, "totExp", "TOTALEXP");
		fd.addField(UNITRANS_COLUMN_SELECT[5], Long.class, UNITRANS_TABLE, "totExpN", "TOTALEXPN");
		fd.addField(UNITRANS_COLUMN_SELECT[6], String.class, UNITRANS_TABLE, "expList", "EXPLIST");
		fd.addField(UNITRANS_COLUMN_SELECT[7], String.class, UNITRANS_TABLE, "expListN", "EXPLISTN");
		
		fd.addField(UNITRANS_COLUMN_SELECT[8], String.class, "HITSTABLE", "HITstr", "HITSTR");
		fd.addField(UNITRANS_COLUMN_SELECT[9], Double.class, UNITRANS_TABLE, "e_value", "EVALUE");
		fd.addField(UNITRANS_COLUMN_SELECT[10], String.class, "HITSTABLE", "description", "BESTHITDESCRIP");
		fd.addField(UNITRANS_COLUMN_SELECT[11], String.class, "HITSTABLE", "species", "BESTHITSPECIES");
		fd.addField(UNITRANS_COLUMN_SELECT[12], String.class, "HITSTABLE", "dbtype", "BESTHITTYPE");
		fd.addField(UNITRANS_COLUMN_SELECT[13], String.class, "HITSTABLE", "taxonomy", "BESTHITTAXO");	
		fd.addField(UNITRANS_COLUMN_SELECT[14], Long.class, "HITSTABLE", "length", "BESTHITLENGTH");

		for(int x=0; x<lib.length; x++) {
			fd.addField(lib[x], Double.class, UNITRANS_TABLE, Globals.PRE_LIB + lib[x], "LIB" + x);
		}
		for(int x=0; x<methods.length; x++) {
			fd.addField(methods[x], String.class, UNITRANS_TABLE, methods[x], "MET" + x);
		}		for(int x=0; x<de.length; x++) {
			fd.addField(de[x], Double.class, UNITRANS_TABLE, Globals.PRE_DE + de[x], "DE" + x);
		}


		fd.addField("AASeq", String.class, UNITRANS_TABLE, "aaSeq", "AASEQ");
		fd.addField("UTID", String.class, UNITRANS_TABLE, "UTid", "UTRANSID");
		
		fd.addJoin("unique_hits", UNITRANS_TABLE + ".HITid = HITSTABLE.HITid", "HITSTABLE");

		return fd;
	}
                 
	//****************************************************************************
	//* Constructors
	//****************************************************************************

	/**
	 * FieldData constructor 
	 */
	public FieldData() {
		theViewFields = new Vector<FieldItem> ();
		theJoins = new Vector<JoinItem> ();
	}
	
	//****************************************************************************
	//* Methods for FieldData
	//****************************************************************************
	
	public int getFieldSymbolPosition(String symbol) {
		int position = -1;
		for(int x=0; x<theViewFields.size() && position < 0; x++) {
			if(theViewFields.get(x).getDBSymbolName().equals(symbol)) {
				position = x;
			}
		}
		return position;
	}
	// get<type>Fields in FieldData
	public void addJoin(String table, String condition, String strSymbol) { 
		theJoins.add(new JoinItem(table, condition, strSymbol)); }
	
	public void setJoins(Vector<JoinItem> joins) {
		if(joins != null) {
			theJoins.clear();
			Iterator<JoinItem> iter = joins.iterator();
			while(iter.hasNext())
				theJoins.add(iter.next());
		}
	}
	
	// getDBFieldQueryList in FieldData
	private String getFieldReference(FieldItem item) {
		String retVal;
		if(item.getDBFieldName() == null) 
			retVal = "NULL";
		else
			retVal = item.getDBTable() + "." + item.getDBFieldName();
		
		if(item.getDBSymbolName().length() > 0)
			retVal += " AS " + item.getDBSymbolName();
		
		return retVal;
	}
	// get<type>Fields in FieldData
	public void addField(	String fieldName, Class<?> type, 
			String dbTable, String dbField, String dbSymbol) {
		FieldItem fd = new FieldItem(fieldName, type);
		fd.setQuery(dbTable, dbField, dbSymbol);
		theViewFields.add(fd);
	}
	//****************************************************************************
	//* Methods  called by ListDataPanel
	//****************************************************************************
	
	// called by builtTable in ListDataPanel
	public String [] getDisplayFields() {
		if(theViewFields.size() == 0) return null;

		Vector<String> retVal = new Vector<String> ();
		Iterator<FieldItem> iter = theViewFields.iterator();
		FieldItem item = null;

		while(iter.hasNext()) {
			item = iter.next();
			String field = item.getFieldName();
			retVal.addElement(field);
		}
		return retVal.toArray(new String[retVal.size()]);
	}
	// buildTable in ListDataPanel
	public Class<?> [] getDisplayTypes() {
		if(theViewFields.size() == 0) return null;

		Vector<Class<?>> retVal = new Vector<Class<?>> ();
		Iterator<FieldItem> iter = theViewFields.iterator();
		FieldItem item = null;

		while(iter.hasNext()) {
			item = iter.next();
			Class<?> type = item.getFieldType();
			retVal.addElement(type);
		}
		return retVal.toArray(new Class<?>[retVal.size()]);
	}
		// loadData in ListDataPanel
	public String getDBFieldQueryList() {
		Iterator<FieldItem> iter = theViewFields.iterator();
		FieldItem item = null;
		if(iter.hasNext()) {
			item = iter.next();
		}
		String retVal = getFieldReference(item);
		
		while(iter.hasNext()) {
			item = iter.next();
			retVal += ", " + getFieldReference(item);
		}
		return retVal;
	}
	// loadData in ListDataPanel
	public boolean hasJoins() { return !theJoins.isEmpty(); }
	// loadData in ListDataPanel
	public String getJoins() { 
		Iterator<JoinItem> iter = theJoins.iterator();
		String retVal = "";
		while(iter.hasNext()) {
			if(retVal.length() == 0)
				retVal = iter.next().getJoin();
			else
				retVal += " " + iter.next().getJoin();
		}
		return retVal;
	}
	/***********************************************
	 * Methods called by TableData
	 */
	// addRowsWithProgress by TableData
	public String [] getDisplayFieldSymbols() {
		if(theViewFields.size() == 0) return null;

		Vector<String> retVal = new Vector<String> ();
		Iterator<FieldItem> iter = theViewFields.iterator();
		FieldItem item = null;

		while(iter.hasNext()) {
			item = iter.next();
			String symbol = item.getDBSymbolName();
			retVal.addElement(symbol);
		}
		return retVal.toArray(new String[retVal.size()]);
	}

	// FieldData local variables
	private Vector<FieldItem> theViewFields = null;
	private Vector<JoinItem> theJoins = null;
	/********************************************************/
	/************************************************
	 * JoinItem class - used by FieldData
	 */
	public class JoinItem {
		public JoinItem(String table, String condition, String symbol) {
			strTable = table;
			strCondition = condition;
			strSymbol = symbol;
		}
		public String getJoin() {
			String retVal = "LEFT JOIN " + strTable;
			if(strSymbol.length() > 0)
				retVal += " AS " + strSymbol;
			retVal += " ON " + strCondition;
			return  retVal;
		}
		private String strTable = "";
		private String strCondition = "";
		private String strSymbol = "";
	}

	/***************************************************
	 * FieldItem class - used by FieldData
	 */
	public class FieldItem {
		public FieldItem(String fieldName, Class<?> type) {
			strFieldName = fieldName;
			cType = type;
 		}

		public void setQuery(String table, String field, String symbol) {
			strDBTable = table;
			strDBField = field;
			strDBSymbol = symbol;
		}

		public String getFieldName() { return strFieldName; }
		public void setFieldName(String name) { strFieldName = name; }

		public Class<?> getFieldType() { return cType; }
		public void setFieldType(Class<?> newType) { cType = newType; }

		public String getDBTable() { return strDBTable; }
		public void setDBTable(String dbTableName) { strDBTable = dbTableName; }

		public String getDBFieldName() { return strDBField; }
		public void setDBFieldName(String dbFieldName) { strDBField = dbFieldName; }
		
		public String getDBSymbolName() { return strDBSymbol; }
		public void setDBSymbolName(String dbSymbol) { strDBSymbol = dbSymbol; }

		//Display name for a table
		private String strFieldName;
		//Data type for the column
		private Class<?> cType = null;
		//True=value read directly from DB, False=value calculated
		//Source table for the value
		private String strDBTable;
		//Source field in the named DB table
		private String strDBField;
		//Symbolic name for query value 
		private String strDBSymbol = "";
	}
}
